package com.ztmao.shortlink.admin.common.biz.user;

import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.ztmao.shortlink.admin.config.UserFlowRiskControlConfiguration;
import com.ztmao.shortlink.admin.convention.exception.ClientException;
import com.ztmao.shortlink.admin.convention.result.Results;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.PathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Optional;

import static com.ztmao.shortlink.admin.common.enums.UserErrorCodeEnum.FLOW_LIMIT_ERROR;

@Slf4j
@RequiredArgsConstructor
public class UserFlowRiskControlFilter implements Filter {
        private final StringRedisTemplate stringRedisTemplate;
        private final UserFlowRiskControlConfiguration userFlowRiskControlConfiguration;

        private static final String USER_FLOW_RISK_CONTROL_LUA_SCRIPT_PATH = "lua/user_flow_risk_control.lua";
        @SneakyThrows
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                redisScript.setScriptSource(new ResourceScriptSource(new PathResource(USER_FLOW_RISK_CONTROL_LUA_SCRIPT_PATH)));
                redisScript.setResultType(Long.class);
                String username = Optional.ofNullable(UserContext.getUsername()).orElse("other");
                Long result = null;
                try {
                        result = stringRedisTemplate.execute(redisScript, Lists.newArrayList(username), userFlowRiskControlConfiguration.getTimeWindow());
                } catch (Throwable ex) {
                        log.error("执行用户请求流量限制LUA脚本出错", ex);
                        returnJson((HttpServletResponse) servletResponse, JSON.toJSONString(Results.failure(new ClientException(FLOW_LIMIT_ERROR))));
                }
                if (result == null || result > userFlowRiskControlConfiguration.getMaxAccessCount()) {
                        returnJson((HttpServletResponse) servletResponse, JSON.toJSONString(Results.failure(new ClientException(FLOW_LIMIT_ERROR))));
                }
                filterChain.doFilter(servletRequest, servletResponse);
        }
        private void returnJson(HttpServletResponse response, String json) throws Exception {
                response.setCharacterEncoding("UTF-8");
                response.setContentType("text/html; charset=utf-8");
                try (PrintWriter writer = response.getWriter()) {
                        writer.print(json);
                }
        }
}
